package org.magnerfuller.imtoolkit.server.session.manager;

import java.util.Vector;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

import org.magnerfuller.imtoolkit.server.session.Session;
import org.magnerfuller.imtoolkit.server.session.event.SessionEvent;
import org.magnerfuller.imtoolkit.server.session.event.listener.SessionEventListener;

/**
 * The class SessionManager is used to manage sessions.
 *
 */
public class SessionManager implements SessionEventListener {
  
  /** sessions -- Sessions to manage */
  private Vector<Session> sessions;
  
  /** sessionsLock -- Synchronize access to the sessions
   * @note A mutex is used here instead of a read-write lock, because
   *       it is expected that sessions will be added and removed from
   *       the vector of managed sessions roughly as often as they are
   *       accessed.  Thus, using a read-write lock would typically result
   *       in starvation, until a batch of readers finish, and a writer
   *       can finally update the sessions. */
  private final Lock sessionsLock = new ReentrantLock();
  
  /**
   * Constructor
   */
  public SessionManager() {
    sessions = new Vector<Session>();
  }//SessionManager
  
  /**
   * Manage a session.
   * 
   * @param session -- The session to manage
   */
  public void manageSession(Session session) {
    sessionsLock.lock();
    try {
      sessions.add(session);
    } finally {
      sessionsLock.unlock();
    }
    session.addSessionEventListener(this);
  }//manageSession
  
  /**
   * Handle an event from a session.  This is used in session management tasks, such
   * as cleaning up resources of sessions.
   * 
   * @param e -- The event
   */
  public void sessionEventOccurred(SessionEvent e) {
    if(e.getType() == SessionEvent.SESSION_TERMINATED_SUCCESS) {
      sessionsLock.lock();
      try {
        if(sessions.remove(e.getSource())) {
          System.err.println("Session " + e.getSource() + " finished.");
        }
      } finally {
        sessionsLock.unlock();
      }
    }
  }//sessionEventOccurred
  
  /**
   * Get the number of sessions currently being managed.
   * 
   * @return the number of managed sessions
   */
  public int getNumSessions() {
    int size = 0;
    sessionsLock.lock();
    try {
      size = sessions.size();
    } finally {
      sessionsLock.unlock();
    }
    return size;
  }//getNumSessions
  
  /**
   * Get the names of the sessions being managed.
   * 
   * @return the session names
   */
  public Vector<String> getSessionNames() {
    Vector<String> sessionNames = new Vector<String>();

    sessionsLock.lock();
    try {
      for(Session session : sessions) {
        sessionNames.addElement(session.toString());
      }
    } finally {
      sessionsLock.unlock();
    }
    
    return sessionNames;
  }//getSessionNames

}//SessionManager
